/*Main entry point for game*/

#include "Box2D/Box2D.h"
#include "OblivionPhysics.h"
#include "GameManager.h"
#include "Display.h"



int WINDOW_W = 600;
int WINDOW_H = 400;

#include <stdlib.h>
#include <cstdio>
#include <vector>
#include <math.h>

#include "GL/glfw.h"

#include "Camera.h"

bool isPaused = false;

struct MouseInputRec {
	glm::vec3 screenPos;
	glm::vec2 worldPos;

	MouseInputRec() {};

	//Get screenPos and worldPos
	MouseInputRec(Camera * inCam, const glm::vec3 & mouse) {

		if (!inCam) {
			return;
		}

		glm::mat4x4 * mv = inCam->GetGLMMat(MODELVIEW_MATRIX);
		glm::mat4x4 * pm = inCam->GetGLMMat(PROJECTION_MATRIX);

		glm::ivec4 view;

		glGetIntegerv(GL_VIEWPORT, &view[0]);

		screenPos = glm::vec3(mouse.x, view[3] - mouse.y, mouse.z);

		glm::vec3 world = glm::unProject(screenPos, *mv, *pm, view);

		worldPos = glm::vec2(world.x, world.y);	
	}
};

MouseInputRec currMousePos;

std::vector<MouseInputRec> addPoints;

GameManager * gm;

Displayer * displayer = NULL;
PhysicsManager * pm = NULL;

b2World * gWorld;

PhysicsPrimitive * ball = NULL;
PhysicsChain * chain = NULL;


/* GLUT callback Handlers */


static void resize(int width, int height)
{
    const float ar = (float) width / (float) height;
    
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
	
	//Set global values
	WINDOW_W = width;
	WINDOW_H = height;
}




void Setup()
{


	glDisable(GL_DEPTH_TEST);
}

void passiveFunc (int x, int y)
{

	currMousePos = MouseInputRec( (displayer->GetCam()), glm::vec3((float)x, (float)y, 1) );

}

/* Program entry point */
void mousefunc (int button, int state, int x, int y){
	return;
}

void keyboardFunc(int x, int y) {
	printf("Keyboardfunc:%d %d\n", x, y);
	glm::vec3 mouse(x, y, 1);
	MouseInputRec mrec(displayer->GetCam(), mouse);
	printf("World: %f %f\n", mrec.worldPos.x, mrec.worldPos.y);
	if (glfwGetKey('V')) {


		printf("ADDING: %d, %d\n", x, y);
		addPoints.push_back(mrec);
	}

	if (glfwGetKey('B')) {
		if ( addPoints.size() <= 1) {
			return;
		}
		std::vector< b2Vec2 > vecs;
		for (int i = 0; i < addPoints.size(); ++i) {
			vecs.push_back( b2Vec2(addPoints[i].worldPos.x, addPoints[i].worldPos.y) );
		}

		PhysicsProperties pp;
		pp.mDensity = 1;
		pp.mElastic = 0;
		pp.mFriction = 1;
		pp.mIsStatic = true;
		pp.mOrigin.Set(0, 0);
		PhysicsChain * newChain = new PhysicsChain(&vecs[0], vecs.size(), pp);

		pm->AddPhysicsObject(newChain);
//		displayer->AddPrimitive(newChain);

		addPoints.clear();
	}
	
	if (glfwGetKey('L')) {
		displayer->GetCam()->SetDoFollow(false);
		displayer->GetCam()->MoveByDelta(glm::vec2(3, 0.0));
	}

	if (glfwGetKey('P')) {
		isPaused = !isPaused;
	}
	
	if (glfwGetKey('D')) {
		ball->AddLinearVelocity(b2Vec2(0.05, 0.0));
	}
	
	if (glfwGetKey('A')) {
		ball->AddLinearVelocity(b2Vec2(-0.05, 0.0));
	}
}

int main(int argc, char *argv[])
{

	gm = new GameManager();
	
	return (gm->Run());
}
